<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>入门</title>
    <!-- 这里可以添加CSS样式文件 -->
  </head>
  <body>
     <script type="importmap">
      {
        "imports": {
          "three": "https://threelab.cn/threejs/build/three.module.js",
          "three/addons/": "https://threelab.cn/threejs/examples/jsm/"
        }
      }
    </script>
    <script type="module">
      import * as THREE from "three"; 
      import { OrbitControls } from "three/addons/controls/OrbitControls.js";
      import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
      import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";
      import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

      

      const scene = new THREE.Scene();

      const camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
      );

      camera.position.set(5, 5, 5);

      const renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true,
        logarithmicDepthBuffer: true,
      });

      renderer.setSize(window.innerWidth, window.innerHeight);

      document.body.appendChild(renderer.domElement);

      new OrbitControls(camera, renderer.domElement);

      window.onresize = () => {
        renderer.setSize(window.innerWidth, window.innerHeight);

        camera.aspect = window.innerWidth / window.innerHeight;

        camera.updateProjectionMatrix();
      };

      const mixerFrames = [];

      animate();

      function animate() {
        requestAnimationFrame(animate);

        mixerFrames.forEach((i) => i?.mixerAnimateRender?.());

        renderer.render(scene, camera);
      }

      scene.add(new THREE.AmbientLight(0xffffff, 4));

      scene.add(new THREE.AxesHelper(1000));

      // 加载模型 gltf/ glb  draco解码器
      const loader = new GLTFLoader();

      loader.setDRACOLoader(
        new DRACOLoader().setDecoderPath(
          "./js/three/draco/"
        )
      );

      loader.load(
        "/files/model/Soldier.glb",

        (gltf) => {
          const group = gltf.scene;

          group.animations = gltf.animations;

          scene.add(group);

          group.actionIndexs = new Array(group.animations.length).fill(false);

          createModeAnimates(group);
        }
      );

      const gui = new GUI();

      // 模型加载完成
      const createModeAnimates = (model) => {
        model.animations.forEach((_, k) => {
          gui.add(
            {
              fn: () => {
                model.actionIndexs.forEach(
                  (_, _k, arr) => (arr[_k] = _k === k)
                );

                modelAnimationPlay(model, model.animations);
              },
            },
            "fn"
          ).name(`单动画${k}`);
        });

        // 多动画
        gui.add(
          {
            fn: () => {
              const _actions = [1, 2]; // 同时播放 第三个和第四个动画

              model.actionIndexs.forEach(
                (_, k, arr) => (arr[k] = _actions.includes(k))
              );

              const { actions } = modelAnimationPlay(model, model.animations);

              setTimeout(() => actions.forEach((v) => v.stop()), 4000);
            },
          },
          "fn"
        ).name("1, 2动画同时播放");
      };

      function modelAnimationPlay(group) {
        const clock = new THREE.Clock();

        const mixer = new THREE.AnimationMixer(group);

        group.mixerAnimateRender = () => {
          const deltaTime = clock.getDelta();

          mixer.update(deltaTime);
        };

        const actions = group.actionIndexs
          .map((i, k) => {
            if (i) {
              const animationAction = mixer.clipAction(group.animations[k]);

              animationAction.loop = THREE.LoopRepeat;

              animationAction.time = 0;

              animationAction.timeScale = 1; // 播放速度

              animationAction.clampWhenFinished = true; //停留到最后一帧

              animationAction.play();

              return animationAction;
            }
          })
          .filter((i) => i);

        !mixerFrames.find((i) => i === group) && mixerFrames.push(group);

        return { actions, mixer };
      }
    </script>
  </body>
</html>
